package com.sservice.service.service.redis;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.*;

import java.util.*;

@Component
public class Redis {
    private static Logger logger = Logger.getLogger(Redis.class);

    @Autowired
    private static JedisPool jedisPool;//

    private static Jedis getJedis() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();

        } catch (Exception e) {
            logger.error("Connection Redis fail. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            jedis.close();
        }

        return jedis;
    }

    /**
     * 发布消息
     *
     * @param channel 频道
     * @param message 消息
     */
    public static void publish(String channel, String message) {
        if (Check.nullOrEmpty(channel) || Check.nullOrEmpty(message)) {
            return;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                jedis.publish(channel, message);
            }
        } catch (Exception e) {
            logger.error(String.format("CALL publish FAIL. Channel:%s, Message:%s, Error: ",
                    channel, message, e.getMessage()));
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }
    }

    /**
     * 订阅消息
     *
     * @param sub      订阅处理
     * @param channels 频道数组
     */
    public static void subscribe(JedisPubSub sub, String... channels) {
        if (sub == null || Check.nullOrEmpty(channels)) {
            return;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                jedis.subscribe(sub, channels);
            }
        } catch (Exception e) {
            logger.error(String.format("CALL subscribe FAIL. Channel:%s, Error: ",
                    channels, e.getMessage()));
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }
    }

    /**
     * 设置键值过期时间
     *
     * @param key     键值
     * @param seconds 过期时间，单位: 秒
     * @return 操作结果<br>
     * true 操作成功<br>
     * false 操作失败
     */
    public static boolean expire(String key, int seconds) {
        if (Check.nullOrEmpty(key) || seconds <= 0) {
            return false;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                return jedis.expire(key, seconds) == 1;
            }
        } catch (Exception e) {
            logger.error("CALL expire FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return false;
    }

    /**
     * 返回指定键值剩余过期时间
     *
     * @param key 键值
     * @return 剩余过期时间，单位秒
     */
    public static long getExpireTime(String key) {
        if (Check.nullOrEmpty(key)) {
            return -1;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                return jedis.ttl(key);
            }
        } catch (Exception e) {
            logger.error("CALL existKey FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return -1;
    }

    public static Set<String> keys(String pattern) {
        if (Check.nullOrEmpty(pattern)) {
            return Collections.emptySet();
        }

        Jedis jedis = getJedis();

        try {
            if (jedis != null) {
                return jedis.keys(pattern);
            }
        } catch (Exception e) {
            logger.error(String.format("CALL keys(%s) FAIL. Error: %s",
                    pattern, e.getMessage()));
        } finally {
            R.closeQuietly(jedis);
        }

        return Collections.emptySet();
    }



    /**
     * 判断KEY是否存在
     *
     * @param key REDIS KEY
     * @return 判断结果<br>
     * true 存在<br>
     * false 不存在<br>
     */
    public static boolean existKey(String key) {
        if (Check.nullOrEmpty(key)) {
            return false;
        }

        Jedis jedis = getJedis();

        try {
            if (jedis != null) {
                return jedis.exists(key);
            }
        } catch (Exception e) {
            logger.error("CALL existKey FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return false;
    }

    /**
     * 判断KEY是否存在
     *
     * @param key REDIS KEY
     * @return 判断结果<br>
     * true 存在<br>
     * false 不存在<br>
     */
    public static boolean existKey(byte[] key) {
        return !Check.nullOrEmpty(key)
                ? existKey(new String(key))
                : false;
    }

    /**
     * 删除REDIS键值
     *
     * @param key REDIS键值
     * @return 操作结果<br>
     * true 操作成功<br>
     * false 操作失败
     */
    public static boolean del(byte[] key) {
        return !Check.nullOrEmpty(key) ? del(new String[]{new String(key)}) : true;
    }

    /**
     * 删除REDIS键值
     *
     * @param key REDIS键值
     * @return 操作结果<br>
     * true 操作成功<br>
     * false 操作失败
     */
    public static boolean del(String key) {
        return !Check.nullOrEmpty(key) ? del(new String[]{key}) : true;
    }

    /**
     * 删除REDIS键值
     *
     * @param keys REDIS键值数组
     * @return 操作结果<br>
     * true 操作成功<br>
     * false 操作失败
     */
    public static boolean del(String[] keys) {
        if (Check.nullOrEmpty(keys)) {
            return true;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                Long v = jedis.del(keys);
                return (v != null) && (v >= 0);
            }
        } catch (Exception e) {
            logger.error("CALL del FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return false;
    }

    /**
     * 删除REDIS键值
     *
     * @param keys REDIS键值集合
     * @return 操作结果<br>
     * true 操作成功<br>
     * false 操作失败
     */
    public static boolean del(Collection<String> keys) {
        return !Check.nullOrEmpty(keys) ? del(keys.toArray(new String[]{})) : false;
    }

    public static String get(String key) {
        if (Check.nullOrEmpty(key)) {
            return "";
        }

        Jedis jedis = getJedis();
        try {
            String s = jedis.get(key);
            return s != null ? s : "";
        } catch (Exception e) {
            logger.error("CALL get FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return "";
    }

    public static boolean set(String key, String value) {
        if (Check.nullOrEmpty(key)) {
            return false;
        }

        Jedis jedis = getJedis();
        try {
            return jedis.set(key, value).equalsIgnoreCase(key);
        } catch (Exception e) {
            logger.error("CALL set FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return false;
    }

    public static long incr(String key) {
        if (Check.nullOrEmpty(key)) {
            return 0L;
        }

        Jedis jedis = getJedis();
        try {
            return jedis.incr(key);
        } catch (Exception e) {
            logger.error("CALL incr FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return 0L;
    }

    public static long incrBy(String key, long value) {
        if (Check.nullOrEmpty(key)) {
            return 0L;
        }

        Jedis jedis = getJedis();
        try {
            return jedis.incrBy(key, value);
        } catch (Exception e) {
            logger.error("CALL incrBy FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return 0L;
    }

    public static long hincrBy(String key, String field, long value) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(field)) {
            return 0L;
        }

        Jedis jedis = getJedis();
        try {
            return jedis.hincrBy(key, field, value);
        } catch (Exception e) {
            logger.error("CALL hincrBy FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return 0L;
    }

    public static long decr(String key) {
        if (Check.nullOrEmpty(key)) {
            return Long.MIN_VALUE;
        }

        Jedis jedis = getJedis();
        try {
            return jedis.decr(key);
        } catch (Exception e) {
            logger.error("CALL decr FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Long.MIN_VALUE;
    }

    public static long decrBy(String key, long value) {
        if (Check.nullOrEmpty(key)) {
            return Long.MIN_VALUE;
        }

        Jedis jedis = getJedis();
        try {
            return jedis.decrBy(key, value);
        } catch (Exception e) {
            logger.error("CALL decrBy FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Long.MIN_VALUE;
    }

    public static boolean lpush(String key, Collection<String> values) {
        if (key == null || key.trim().length() == 0
                || values == null || values.size() == 0) {
            return false;
        }

        Jedis jedis = getJedis();

        Pipeline pipeline = null;
        try {
            if (jedis != null) {
                pipeline = jedis.pipelined();
                pipeline.lpush(key, values.toArray(new String[0]));
                pipeline.sync();

                return true;
            }
        } catch (Exception e) {
            logger.error("CALL lpush FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (pipeline != null) {
                pipeline.clear();
            }

            R.closeQuietly(pipeline);
            R.closeQuietly(jedis);
        }

        return false;
    }

    public static boolean lpush(String key, String value) {
        return lpush(key, Arrays.asList(value));
    }

    public static boolean lpush(byte[] key, Collection<byte[]> values) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(values)) {
            return false;
        }

        Jedis jedis = getJedis();

        Pipeline pipeline = null;
        try {
            if (jedis != null) {
                pipeline = jedis.pipelined();

                byte[][] bs = new byte[values.size()][];

                int i = 0;
                for (byte[] data : values) {
                    if (data != null) {
                        bs[i] = data;
                        i++;
                    }
                }

                pipeline.lpush(key, bs);
                pipeline.sync();

                return true;
            }
        } catch (Exception e) {
            logger.error("CALL lpush FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (pipeline != null) {
                pipeline.clear();
            }

            R.closeQuietly(pipeline);
            R.closeQuietly(jedis);
        }

        return false;
    }

    public static boolean lpush(byte[] key, byte[] value) {
        return lpush(key, value != null ? Arrays.asList(value) : null);
    }

    public static boolean lpush(Map<byte[], byte[]> map) {
        if (Check.nullOrEmpty(map)) {
            return false;
        }

        Jedis jedis = getJedis();
        Pipeline pipeline = null;
        try {
            if (jedis != null) {
                pipeline = jedis.pipelined();
                for (byte[] key : map.keySet()) {
                    pipeline.lpush(key, map.get(key));
                }
                pipeline.sync();

                return true;
            }
        } catch (Exception e) {
            logger.error("CALL lpush FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (pipeline != null) {
                pipeline.clear();
            }

            R.closeQuietly(pipeline);
            R.closeQuietly(jedis);
        }

        return false;
    }

    public static List<byte[]> lpop(byte[] key, int size) {
        if (Check.nullOrEmpty(key) || size <= 0) {
            return Collections.emptyList();
        }

        Jedis jedis = getJedis();
        Pipeline pipe = null;
        try {
            if (jedis != null) {
                if (!jedis.exists(key)) {
                    return Collections.emptyList();
                }

                pipe = jedis.pipelined();

                List<Response<byte[]>> rsps = new LinkedList<>();
                for (int i = 0; i < size; i++) {
                    Response<byte[]> rsp = pipe.lpop(key);
                    if (rsp == null) {
                        break;
                    }

                    rsps.add(rsp);
                }
                pipe.sync();

                List<byte[]> list = new LinkedList<>();
                for (Response<byte[]> r : rsps) {
                    byte[] arr = r.get();
                    if (arr == null || arr.length == 0) {
                        break;
                    }

                    list.add(arr);
                }

                return list;
            }
        } catch (Exception e) {
            logger.error("CALL lpush FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (pipe != null) {
                pipe.clear();
            }

            R.closeQuietly(pipe);
            R.closeQuietly(jedis);
        }

        return Collections.emptyList();
    }

    public static byte[] lpop(byte[] key) {
        List<byte[]> list = lpop(key, 1);
        return !Check.nullOrEmpty(list) ? list.get(0) : null;
    }

    public static List<String> lpop(String key, int size) {
        if (Check.nullOrEmpty(key) || size <= 0) {
            return Collections.emptyList();
        }

        Jedis jedis = getJedis();
        Pipeline pipe = null;
        try {
            if (jedis != null) {
                if (!jedis.exists(key)) {
                    return Collections.emptyList();
                }

                pipe = jedis.pipelined();

                List<Response<String>> response = new LinkedList<>();
                for (int i = 0; i < size; i++) {
                    Response<String> rsp = pipe.lpop(key);
                    if (rsp == null) {
                        break;
                    }
                    response.add(rsp);
                }
                pipe.sync();

                List<String> list = new LinkedList<>();
                for (Response<String> r : response) {
                    String s = r.get();
                    if (s == null || s.equalsIgnoreCase("")) {
                        break;
                    }
                    list.add(s);
                }

                return list;
            }
        } catch (Exception e) {
            logger.error("CALL lpop FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (pipe != null) {
                pipe.clear();
            }

            R.closeQuietly(pipe);
            R.closeQuietly(jedis);
        }

        return Collections.emptyList();
    }

    public static String lpop(String key) {
        List<String> list = lpop(key, 1);
        return list == null || list.size() == 0 ? "" : list.get(0);
    }

    public static List<String> lrange(String key, long start, long end) {
        if (Check.nullOrEmpty(key)) {
            return Collections.emptyList();
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                List<String> result = jedis.lrange(key, start, end);
                return result != null ? result : Collections.emptyList();
            }
        } catch (Exception e) {
            logger.error("CALL lrange FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Collections.emptyList();
    }

    public static List<byte[]> lrange(byte[] key, long start, long end) {
        if (Check.nullOrEmpty(key)) {
            return Collections.emptyList();
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                List<byte[]> result = jedis.lrange(key, start, end);
                return result != null ? result : Collections.emptyList();
            }
        } catch (Exception e) {
            logger.error("CALL lrange FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Collections.emptyList();
    }

    /**
     * 获取列表长度
     *
     * @param key 键值
     * @return 列表长度
     */
    public static long llen(String key) {
        if (Check.nullOrEmpty(key)) {
            return 0;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                Long v = jedis.llen(key);
                return v != null ? v.longValue() : 0;
            }
        } catch (Exception e) {
            logger.error("CALL existKey FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return 0;
    }

    public static List<byte[]> rpop(byte[] key, int size) {
        if (Check.nullOrEmpty(key) || size <= 0) {
            return Collections.emptyList();
        }

        Jedis jedis = getJedis();
        Pipeline pipe = null;

        List<byte[]> list = new LinkedList<>();
        List<Response<byte[]>> rsps = new LinkedList<>();
        try {
            if (jedis != null) {
                if (!jedis.exists(key)) {
                    return Collections.emptyList();
                }

                pipe = jedis.pipelined();
                for (int i = 0; i < size; i++) {
                    Response<byte[]> rsp = pipe.rpop(key);
                    if (rsp == null) {
                        break;
                    }
                    rsps.add(rsp);
                }
                pipe.sync();

                for (Response<byte[]> r : rsps) {
                    byte[] arr = r.get();
                    if (arr == null || arr.length == 0) {
                        break;
                    }
                    list.add(arr);
                }
            }
        } catch (Exception e) {
            logger.error("CALL rpop FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(pipe);
            R.closeQuietly(jedis);
        }

        return list;
    }

    public static boolean hmset(String key, Map<String, String> map) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(map)) {
            return false;
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                return jedis.hmset(key, map).equalsIgnoreCase("OK");
            }
        } catch (Exception e) {
            logger.error("CALL hmset FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return false;
    }

    public static List<String> hmget(String key, List<String> fields) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(fields)) {
            return Collections.emptyList();
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                return jedis.hmget(key, fields.toArray(new String[0]));
            }
        } catch (Exception e) {
            logger.error("CALL hmget FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Collections.emptyList();
    }

    public static boolean hset(String key, String field, String value) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(field)) {
            return false;
        }

        Jedis jedis = getJedis();

        try {
            if (jedis != null) {
                return jedis.hset(key, field, value) > 0;
            }
        } catch (Exception e) {
            logger.error("CALL hset FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return false;

    }

    public static String hget(String key, String field) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(field)) {
            return "";
        }

        String value = null;

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                value = jedis.hget(key, field);
            }
        } catch (Exception e) {
            logger.error("CALL hget FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return value != null ? value : "";
    }

    public static Map<String, String> hgets(String key, String[] fields) {
        if (Check.nullOrEmpty(key) || Check.nullOrEmpty(fields)) {
            return Collections.emptyMap();
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                List<String> values = jedis.hmget(key, fields);
                if (values != null && values.size() == fields.length) {
                    Map<String, String> map = new LinkedHashMap<>();
                    for (int i = 0; i < fields.length; i++) {
                        map.put(fields[i], values.get(i));
                    }

                    return map;
                }
            }
        } catch (Exception e) {
            logger.error("CALL hget FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Collections.emptyMap();
    }

    public static Map<String, String> hgetAll(String key) {
        if (Check.nullOrEmpty(key)) {
            return Collections.emptyMap();
        }

        Jedis jedis = getJedis();
        try {
            if (jedis != null) {
                return jedis.hgetAll(key);
            }
        } catch (Exception e) {
            logger.error("CALL hgetall FAIL. Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            R.closeQuietly(jedis);
        }

        return Collections.emptyMap();
    }

    public static void main(String[] args) {
        Set<String> keys = Redis.keys("*");
        System.out.println(keys);
    }



    @Autowired
    public void setJedisPool(JedisPool jedisPool) {
        Redis.jedisPool = jedisPool;
    }
}